<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" >

<title>JS闭包的应用实例 | 没想好的个人博客</title>

<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">

<!-- <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous"> -->
   <!-- Font Awesome CSS-->
   <link href="https://cdn.bootcss.com/font-awesome/5.13.0/css/all.css" rel="stylesheet">

   <link rel="stylesheet" href="https://cdn.bootcss.com/font-awesome/5.7.2/css/all.min.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">

<link rel="shortcut icon" href="https://shixixiyue.gitee.io//favicon.ico?v=1709791195950">
<link rel="stylesheet" href="https://shixixiyue.gitee.io//styles/main.css">



<link rel="stylesheet" href="https://unpkg.com/aos@next/dist/aos.css" />
<script src="https://jsd.onmicrosoft.cn/npm/vue/dist/vue.js"></script>


<style>
  .hljs-ln{
    padding-bottom: 1.2rem;
    margin: 0rem !important;
  }
  .hljs-ln td {
    border: none !important;
    padding: 2px 6px !important;
    line-height: 1.2rem;
    font-size: 1rem;
  }
  .hljs-ln tr td:first-child  {
    color: cadetblue;
    border-right: 1px solid !important;
  }
  .hljs-ln tr {
    border: none !important;
  }
</style>

    <meta name="description" content="昨天使用FineUIGrid写了一个购物车，主要是改变数量和单价计算总价的功能，纯前端。在实现时遇到了坑，解决后使用了闭包的结构优化，这里推演下应用的过程








1. 代码概览
2. 问题
3. 优化








1. 代码概..." />
    <meta name="keywords" content="其他,FineUICore" />
  </head>
  <body>
    <div id="app" class="main">

      <div class="sidebar" :class="{ 'full-height': menuVisible }">
  <div class="top-container" data-aos="fade-right">
    <div class="top-header-container">
      <a class="site-title-container" href="https://shixixiyue.gitee.io/">
        <img src="https://shixixiyue.gitee.io//images/avatar.png?v=1709791195950" class="site-logo">
        <h1 class="site-title">没想好的个人博客</h1>
      </a>
      <div class="menu-btn" @click="menuVisible = !menuVisible">
        <div class="line"></div>
      </div>
    </div>
    <div>
      
        
          <a href="https://shixixiyue.gitee.io/" class="site-nav">
            首页
          </a>
        
      
        
          <a href="https://shixixiyue.gitee.io//tag/4gOKry8Qv/" class="site-nav">
            .Net Core
          </a>
        
      
        
          <a href="https://shixixiyue.gitee.io//tag/njETBpqXu/" class="site-nav">
            FineUICore
          </a>
        
      
        
          <a href="https://shixixiyue.gitee.io//tag/XyXyeLOBB" class="site-nav">
            读书笔记
          </a>
        
      
        
          <a href="https://shixixiyue.gitee.io//tag/TyVX6hfCJ" class="site-nav">
            Vue笔记
          </a>
        
      
        
          <a href="https://shixixiyue.gitee.io//tag/3Hz2sPtzO/" class="site-nav">
            产品
          </a>
        
      
        
          <a href="https://shixixiyue.gitee.io//tag/Db1wShB_E" class="site-nav">
            其他
          </a>
        
      
        
          <a href="https://shixixiyue.gitee.io/" class="site-nav">
            一一一一一一一一一
          </a>
        
      
        
          <a href="https://shixixiyue.gitee.io//archives" class="site-nav">
            文章归档
          </a>
        
      
        
          <a href="https://shixixiyue.gitee.io//tags" class="site-nav">
            全部标签
          </a>
        
      
    </div>
  </div>
  <div class="bottom-container" data-aos="flip-up" data-aos-offset="0">
    <div class="social-container">
      
        
      
        
      
        
      
        
      
        
      
    </div>
    <div class="site-description">
      没事啥都说
    </div>
    <div class="site-footer">
      QQ：<a href="tencent://message/?uin=935732994&Site=''&Menu=yes">935732994<a/> <a href="http://beian.miit.gov.cn">京ICP备2024045283号<a/> | <a class="rss" href="https://shixixiyue.gitee.io//atom.xml" target="_blank">RSS</a>
    </div>
  </div>
</div>


      <div class="main-container">
        <div class="content-container" data-aos="fade-up">
          <div class="post-detail">
            <h2 class="post-title">JS闭包的应用实例</h2>
            <div class="post-date">2023-08-17
            
                
                  <a href="https://shixixiyue.gitee.io/tag/Db1wShB_E/" class="tag">
                    其他
                  </a>
                
                  <a href="https://shixixiyue.gitee.io/tag/njETBpqXu/" class="tag">
                    FineUICore
                  </a>
                
            </div>
            
              <div class="feature-container" style="background-image: url('https://shixixiyue.gitee.io//post-images/js-bi-bao-ying-yong.png')">
              </div>
            
            <div class="post-content" v-pre>
              <p>昨天使用FineUIGrid写了一个购物车，主要是改变数量和单价计算总价的功能，纯前端。在实现时遇到了坑，解决后使用了闭包的结构优化，这里推演下应用的过程</p>
<!-- more -->
<p><ul class="markdownIt-TOC">
<li>
<ul>
<li>
<ul>
<li>
<ul>
<li><a href="#1-%E4%BB%A3%E7%A0%81%E6%A6%82%E8%A7%88">1. 代码概览</a></li>
<li><a href="#2-%E9%97%AE%E9%A2%98">2. 问题</a></li>
<li><a href="#3-%E4%BC%98%E5%8C%96">3. 优化</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</p>
<h4 id="1-代码概览">1. 代码概览</h4>
<p>首先购物车需要两个列，数量和单价，可以编辑，这里使用了 <code>RendererFunction</code> 进行绘制，绘制函数就是返回个 <code>input</code> 标签<br>
购物车的项需要新增和删除，这里对应两个方法 <code>adddata</code> 和 <code>removedata</code>，在修改数据后需要计算合计价格:<code>updateTotal</code> ，所以有代码如下，这里抽象一下，细节不重要</p>
<pre><code>/**绘制输入数量*/
const renderNumber = function(v, { rowId, rowValue }, m, g){
     return `&lt;input  id=&quot;Number_${rowId}&quot; value=&quot;${v}&quot; class=&quot;number&quot; style=&quot;width:98%;&quot; type=&quot;text&quot;&gt;`;
}
</code></pre>
<pre><code>/**
 * 新增方法
 * @param {[MsINVMB]} values 新增的数据数组
 */
function adddata(values){
    F.ui.Grid1.addNewRecords(data, true);
    //更新总价
    updateTotal();
}
</code></pre>
<pre><code>/**
 * 删除方法
 * @param {ID} rowId 删除的ID
 */
function removedata(rowId){
    F.ui.Grid1.deleteRow(rowId, true);
    //更新总价
    updateTotal();
}
</code></pre>
<pre><code>/**
 * 更新总价
 */
function updateTotal(){
    //计算总价
    let res = GetSummary();
    //更新总价
    F.ui.Grid1.setSummaryData(res);
}
</code></pre>
<h4 id="2-问题">2. 问题</h4>
<p>熟悉FineUI前端的能感觉到坑来了，调用过 <code>addNewRecords</code> 或 <code>deleteRow</code> 的同学都知道，这两个方法会重绘Grid，即触发 <code>renderNumber</code> 函数，造成输入的值会被重置，比如我在某行的数量输入了2，然后新增了一行，执行 <code>addNewRecords</code> ，然后输入的2没了，成默认项了，这时总价也不对了；这里不讨论为什么会触发绘制，对外可能是逆天的，但是对内是自洽的；<br>
最直接的解决方法就是在 新增 或 删除 行之前先得到录入的值，执行新增后再给赋上，然后计算总价；所以多了两个方法 <code>GetInputVal</code> 和 <code>SetInputVal</code> ，改造如下;</p>
<pre><code>/**
 * 新增方法
 * @param {[MsINVMB]} values 新增的数据数组
 */
function adddata(values){
    let rawvalue = GetInputVal();
    F.ui.Grid1.addNewRecords(data, true);
    SetInputVal(rawvalue);
    //更新总价
    updateTotal();
}

/**
 * 删除方法
 * @param {ID} rowId 删除的ID
 */
function removedata(rowId){
    let rawvalue = GetInputVal();
    F.ui.Grid1.deleteRow(rowId, true);
    SetInputVal(rawvalue);
    //更新总价
    updateTotal();
}
</code></pre>
<h4 id="3-优化">3. 优化</h4>
<p>这时让我别扭的地方来了，我最讨厌割裂，明显 <code>GetInputVal</code> 和 <code>SetInputVal</code> 是一对，在调用时中间间隔其他的逻辑，而且他俩本身不参与其他逻辑，<code>SetInputVal</code> 只接收 <code>GetInputVal</code> 返回的值，<code>rawvalue</code> 外露没有意义还有可能被篡改，所以我感觉他俩应该是一个函数，为什么方法我还要写两个，我能不能塞到一个函数里，并且中间还可以跨其他的逻辑；</p>
<pre><code>/**得到值*/
function GetInputVal(){}
/**设置值*/
function SetInputVal(values){}
</code></pre>
<p>这个场景下，我想到了使用闭包的方式，有一个函数 <code>RestoreInputVal</code> ，如果要跨过其他逻辑，这个函数返回的应该是 <code>SetInputVal</code> 的实现而不是调用，它应该这么写</p>
<pre><code>/**还原值*/
function RestoreInputVal(){
    const GetInputVal = ()=&gt;...;
    const SetInputVal = (values)=&gt;...;
    let rawvalue = GetInputVal();
    return ()=&gt;{
        SetInputVal(rawvalue);
    };
}
</code></pre>
<p>用的时候像这样</p>
<pre><code>/**
 * 新增方法
 * @param {[MsINVMB]} values 新增的数据数组
 */
function adddata(values){
    let restorval = RestoreInputVal();
    F.ui.Grid1.addNewRecords(data, true);
    restorval();
    //更新总价
    updateTotal();
}

/**
 * 删除方法
 * @param {ID} rowId 删除的ID
 */
function removedata(rowId){
    let restorval = RestoreInputVal();
    F.ui.Grid1.deleteRow(rowId, true);
    restorval();
    //更新总价
    updateTotal();
}
</code></pre>
<p>这样就实现了 <code>rawvalue</code> 的闭包，以此作为一个典型的应用案例</p>
<p>其实要按照面向对象的思路应该是一个 class ,这里也不考虑继承扩展，所以就不深入了</p>
<pre><code>class InputRestore {

  #rawValue;

  constructor() {
    this.#rawValue = this.#getInputValue(); 
  }

  #getInputValue() {
    // 原逻辑
  }

  #setInputValue(value) {
   // 原逻辑 
  }

  restore() {
    this.#setInputValue(this.#rawValue);
  }

}
</code></pre>

            </div>
            
              <div class="tag-container">
                
                  <a href="https://shixixiyue.gitee.io/tag/Db1wShB_E/" class="tag">
                    其他
                  </a>
                
                  <a href="https://shixixiyue.gitee.io/tag/njETBpqXu/" class="tag">
                    FineUICore
                  </a>
                
              </div>
            
            
              <div class="next-post">
                <div class="next">下一篇</div>
                <a href="https://shixixiyue.gitee.io/yi-lai-zhu-ru-zuo-yong-yu-scopede-ce-shi/">
                  <h3 class="post-title">
                    依赖注入作用域(Scope)的测试
                  </h3>
                </a>
              </div>
            

            

          </div>

        </div>
      </div>
    </div>

    <script src="https://unpkg.com/aos@next/dist/aos.js"></script>
<script type="application/javascript">

AOS.init();

var app = new Vue({
  el: '#app',
  data: {
    menuVisible: false,
  },
})

</script>


  <script src="//jsd.onmicrosoft.cn/gh/highlightjs/cdn-release@11.5.1/build/highlight.min.js"></script>
  <script>
    hljs.initHighlightingOnLoad();
    //hljs.registerLanguage('mermaid', window.hljsDefineMermaid);
  </script>
  <script src="//jsd.onmicrosoft.cn/npm/highlightjs-line-numbers.js@2.8.0/dist/highlightjs-line-numbers.min.js"></script>
  <script>
    hljs.initLineNumbersOnLoad({
      singleLine: true
    });
  </script>
 <script src="https://jsd.onmicrosoft.cn/npm/mermaid/dist/mermaid.min.js"></script>
   <script>
    mermaid.initialize({
      startOnLoad: true,
      securityLevel: 'loose',
    });
  </script>





  </body>
</html>
